// re2c $INPUT -o $OUTPUT --recursive-functions -i
#include <assert.h>
#include <stdio.h>
#include <string.h>

/*!max:re2c*/
#define SIZE 4096

typedef struct {
    FILE *file;
    char buf[SIZE + YYMAXFILL], *lim, *cur, *mar, *tok;
    int eof;
} Input;

static int fill(Input *in, size_t need)
{
    if (in->eof) {
        return 1;
    }
    const size_t free = in->tok - in->buf;
    if (free < need) {
        return 2;
    }
    memmove(in->buf, in->tok, in->lim - in->tok);
    in->lim -= free;
    in->cur -= free;
    in->mar -= free;
    in->tok -= free;
    in->lim += fread(in->lim, 1, free, in->file);
    if (in->lim < in->buf + SIZE) {
        in->eof = 1;
        memset(in->lim, 0, YYMAXFILL);
        in->lim += YYMAXFILL;
    }
    return 0;
}

static void init(Input *in, FILE *file)
{
    in->file = file;
    in->cur = in->mar = in->tok = in->lim = in->buf + SIZE;
    in->eof = 0;
    fill(in, 1);
}

static int lex_loop(Input *in, int count);

/*!re2c
re2c:api:style = free-form;
re2c:define:YYFN     = ["lex;static int", "in;Input*", "count;int"];
re2c:define:YYCTYPE  = char;
re2c:define:YYCURSOR = in->cur;
re2c:define:YYMARKER = in->mar;
re2c:define:YYLIMIT  = in->lim;
re2c:define:YYFILL   = "if (fill(in, @@) != 0) return -1;";

*                           { return -1; }
[\x00]                      { return (in->lim - in->cur == YYMAXFILL - 1) ? count : -1; }
['] ([^'\\] | [\\][^])* ['] { return lex_loop(in, ++count); }
[ ]+                        { return lex_loop(in, count); }

*/

static int lex_loop(Input *in, int count)
{;
    in->tok = in->cur;
    return lex(in, count);
}

int main()
{
    const char *fname = "input";
    const char str[] = "'qu\0tes' 'are' 'fine: \\'' ";
    FILE *f;
    Input in;

    // prepare input file: a few times the size of the buffer,
    // containing strings with zeroes and escaped quotes
    f = fopen(fname, "w");
    for (int i = 0; i < SIZE; ++i) {
        fwrite(str, 1, sizeof(str) - 1, f);
    }
    fclose(f);

    f = fopen(fname, "r");
    init(&in, f);
    assert(lex_loop(&in, 0) == SIZE * 3);
    fclose(f);

    remove(fname);
    return 0;
}
